package com.example.chess.game;

import com.example.chess.mapper.UserMapper;
import com.example.chess.model.User;
import com.example.chess.util.MatchResponse;
import com.example.chess.util.ResState;
import com.example.chess.util.ResponseBody;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

/**
 * 匹配机制
 */
@Component
@Data
public class Matcher {
    private Queue<User> bronze = new LinkedList<>();// 青铜队列 积分在 [1000, 2000)
    private Queue<User> gold = new LinkedList<>();// 黄金队列 积分在 [2000, 3000)
    private Queue<User> king = new LinkedList<>();// 王者队列 积分在 [3000, ...)

    private ObjectMapper objectMapper = new ObjectMapper();

    @Resource
    private OnlineUserManager onlineUserManager;

    @Resource
    private RoomManager roomManager;



    // 将玩家进入对应的匹配队列
    public void enterQueue(User user){
        if (user.getScore() < 2000){
            synchronized (bronze){
                bronze.add(user);
                bronze.notify();// 当有玩家匹配时, 唤醒一次扫描线程
            }
            System.out.println("把玩家 " + user.getNickname() + "添加进青铜队列");
        }else if (user.getScore() < 3000){
            synchronized (gold){
                gold.offer(user);
                gold.notify();
            }
            System.out.println("把玩家 " + user.getNickname() + "添加进黄金队列");
        }else {
            synchronized (gold){
                king.add(user);
                king.notify();
            }
            System.out.println("把玩家 " + user.getNickname() + "添加进王者队列");
        }
    }

    // 停止匹配, 移出匹配队列
    public void quit(User user){
        if (user.getScore() < 2000){
            synchronized (bronze){
                bronze.remove(user);
            }
            System.out.println("把玩家 " + user.getNickname() + "移除青铜队列");
        }else if (user.getScore() < 3000){
            synchronized (gold){
                gold.remove(user);
            }
            System.out.println("把玩家 " + user.getNickname() + "移除黄金队列");
        }else {
            synchronized (gold){
                king.remove(user);
            }
            System.out.println("把玩家 " + user.getNickname() + "移除王者队列");
        }
    }

    // 匹配 , 创建三个线程, 分别对三个队列进行扫描
    public Matcher(){
        Thread bronzeThread = new Thread() {
            @Override
            public void run() {
                // 扫描 bronzeQueue
                while (true){
                    scanQueue(bronze);
                }
            }
        };
        bronzeThread.start();
        Thread goldThread = new Thread() {
            @Override
            public void run() {
                while (true){
                    scanQueue(gold);
                }
            }
        };
        goldThread.start();
        Thread kingThread = new Thread() {
            @Override
            public void run() {
                while (true){
                    scanQueue(king);
                }
            }
        };
        kingThread.start();
    }

    private void scanQueue(Queue<User> matchQueue) {
        synchronized (matchQueue){
            try {
                // 当有一个玩家进入时, 唤醒, 但是条件仍然不满足, 继续进入循环等待匹配
                while (matchQueue.size() < 2){
                    // 当有玩家匹配时, 唤醒一次扫描线程
                    matchQueue.wait();
                }

                // 取出两个玩家
                User player1 = matchQueue.poll();
                User player2 = matchQueue.poll();

                System.out.println("匹配成功: " + player1 + "\n" +  player2);

                // 获取玩家信息
                WebSocketSession session1 = onlineUserManager.getSession(player1.getUserId());
                WebSocketSession session2 = onlineUserManager.getSession(player2.getUserId());

                if (session1 == null){
                    // 玩家一下线, 将玩家二重新加到匹配队列
                    matchQueue.offer(player2);
                    return;
                }
                if (session2 == null){
                    // 玩家二下线, 将玩家一重新加到匹配队列
                    matchQueue.offer(player1);
                    return;
                }
                // 是同一个会话
                if (session1 == session2){
                    matchQueue.offer(player1);
                    return;
                }

                // 将两个玩家放到同一个游戏房间
                Room room = new Room();
                roomManager.add(room, player1.getUserId(), player2.getUserId());

                // 给玩家反馈匹配成功的信息
                // 给玩家一发送
                session1.sendMessage(new TextMessage(
                        objectMapper.writeValueAsString(
                                new MatchResponse(ResState.SUCCESS, "匹配成功", "matchSuccess"))));

                // 给玩家二发送
                session2.sendMessage(new TextMessage(
                        objectMapper.writeValueAsString(
                                new MatchResponse(ResState.SUCCESS, "匹配成功", "matchSuccess"))));
            } catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
